package org.java.mathgame.screens;


import com.badlogic.gdx.Screen;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
import com.badlogic.gdx.scenes.scene2d.Actor;
import com.badlogic.gdx.scenes.scene2d.InputEvent;
import com.badlogic.gdx.scenes.scene2d.InputListener;
import com.badlogic.gdx.scenes.scene2d.Stage;
import com.badlogic.gdx.scenes.scene2d.ui.Label;
import com.badlogic.gdx.scenes.scene2d.ui.Skin;
import com.badlogic.gdx.scenes.scene2d.ui.Table;
import com.badlogic.gdx.scenes.scene2d.ui.TextButton;
import com.badlogic.gdx.scenes.scene2d.ui.ImageButton;
import com.badlogic.gdx.scenes.scene2d.utils.Drawable;
import com.esotericsoftware.tablelayout.Cell;
import org.java.mathgame.*;
import com.badlogic.gdx.graphics.g2d.BitmapFont;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.graphics.GL10;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

// TODO
// put grid code in a seperate grid class
// and implement the grid object

// TODO
// organize code that is used more than once in seperate methods
// same goes for putting things in methods if it makes the code more readable

// TODO
// difficulty levels

// TODO
// game modes

public class GameScreen implements Screen {
    private MathGame game;
    private SpriteBatch spriteBatch;
    private BitmapFont font;
    public static Table table;
    private Stage stage;
    private int gridSize;
    private String output;
    private String equation;
    private int safeTimer;
    private float cellSize;
    private Grid grid;
    private ArrayList<TextButton.TextButtonStyle> gridButtonStyles;
    private ArrayList<TextButton.TextButtonStyle> operatorButtonStyles;
    private Random random = new Random();
    private Table rootTable;
    private TextButton goalButton;

    // constructor to keep a reference to the main Game class
    public GameScreen(MathGame game) {
        this.game = game;
        output = "";
        equation = "";
        gridSize = 5;
        cellSize = Gdx.graphics.getWidth()/gridSize;
        spriteBatch = new SpriteBatch();
        font = new BitmapFont();

        FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("data/DroidSansMono.ttf"));
        BitmapFont buttonFont = generator.generateFont((int) (cellSize/2.5));
        generator.dispose();

        TextButton.TextButtonStyle gridButtonStyle = new TextButton.TextButtonStyle();
        TextButton.TextButtonStyle operatorButtonStyle;
        Color[] colors = new Color[]{
                new Color(210 / 255f, 57 / 255f, 59 / 255f, 1),
                new Color(58 / 255f, 143 / 255f, 208 / 255f, 1),
                new Color(59 / 255f, 209 / 255f, 112 / 255f, 1),
                new Color(208 / 255f, 147 / 255f, 58 / 255f, 1)};
        Color[] darkColors = new Color[]{
                new Color(162 / 255f, 9 / 255f, 11 / 255f, 1),
                new Color(10 / 255f, 95 / 255f, 160 / 255f, 1),
                new Color(11 / 255f, 161 / 255f, 62 / 255f, 1),
                new Color(162 / 255f, 98 / 255f, 10 / 255f, 1)};
        Color[] lightColors = new Color[]{
                new Color(217 / 255f, 157 / 255f, 157 / 255f, 1),
                new Color(161 / 255f, 213 / 255f, 239 / 255f, 1),
                new Color(165 / 255f, 240 / 255f, 200 / 255f, 1),
                new Color(232 / 255f, 199 / 255f, 130 / 255f, 1)};
        gridButtonStyles = new ArrayList<TextButton.TextButtonStyle>();
        int styleNumber = random.nextInt(4);
        for (int i = 0; i < 4; i++) {
            TextButton.TextButtonStyle style = new TextButton.TextButtonStyle();
            style.font = buttonFont;
            style.pressedOffsetX = 1;
            style.pressedOffsetY = -1;
            style.font.setColor(Color.WHITE);
            style.up = new ButtonBackground(colors[i]);
            style.down = new ButtonBackground(darkColors[i]);
            style.checked = new ButtonBackground(lightColors[i]);
            gridButtonStyles.add(style);
        }
        operatorButtonStyles = new ArrayList<TextButton.TextButtonStyle>();
        for (int i = 0; i < 4; i++) {
            TextButton.TextButtonStyle style = new TextButton.TextButtonStyle();
            style.font = buttonFont;
            style.pressedOffsetX = 1;
            style.pressedOffsetY = -1;
            style.font.setColor(Color.WHITE);
            style.up = new ButtonBackground(darkColors[i]);
            style.down = new ButtonBackground(colors[i]);
            style.checked = new ButtonBackground(lightColors[i]);
            operatorButtonStyles.add(style);
        }

        operatorButtonStyle = operatorButtonStyles.get(styleNumber) ;
        gridButtonStyle = gridButtonStyles.get(styleNumber) ;


        grid = new Grid(this, gridSize);
        random = new Random();

        table = new Table();
        stage = new Stage();
        for (int i = 0; i < gridSize; i++) {
            for (int j = 0; j < gridSize; j++) {
                TextButton button;
                // TODO
                // currently, on average, half of the grid is covered in operators and half is in numbers
                // reduce the number of operators
                button = new TextButton(grid.getGridElement(i, j).getValue(), gridButtonStyle);
                button.setName(i + "," + j);
                button.addListener(new InputListener() {
                    public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
                        return true;
                    }

                    public void touchUp(InputEvent event, float x, float y, int pointer, int button) {
                        Actor sender = event.getListenerActor();
                        output = ("button (" + sender.getName() + ") up");
                        TextButton pressedButton = (TextButton) sender;
                        pressedButton.setChecked(true);
                        grid.Update(pressedButton);
                         goalButton.setText(Integer.toString(grid.getResult()));

                    }
                });
                if (grid.isOperator(grid.getGridElement(i,j).getValue())){
                    button.setStyle(operatorButtonStyle);
                }
                if ((j>0)&&(grid.getGridElement(i, j - 1).getValue().equals(grid.getGridElement(i, j).getValue()))&&grid.isOperator(grid.getGridElement(i,j).getValue())) {
                    List<Cell> cells = table.getCells();
                    Cell cell = cells.get(cells.size()-1);
                    cell.width(2*cellSize).colspan(2);//.width(2 * Gdx.graphics.getWidth() / gridSize);
                    cell.align(1);
                }
                else {
                    table.add(button).width(cellSize - 10).height(cellSize - 10).space(10);
                }

            }
            table.row();
        }
        table.setBounds(0, table.getHeight(), Gdx.graphics.getWidth(), Gdx.graphics.getWidth());
        table.center();
        table.pad(0,10,10,10);

        Label.LabelStyle labelStyle = new Label.LabelStyle();  //TODO: make a new style
        labelStyle.font = new BitmapFont();
        Table infoTable = new Table();
        Table infoLeft = new Table();
        Table infoRight = new Table();
        //infoRight.setFillParent(true);
        //infoLeft.setFillParent(true);
        Label goalLabel = new Label("GOAL",labelStyle);
        Label scoreLabel = new Label("SCORE",labelStyle);
        Label timerLabel = new Label("TIME",labelStyle);
        Label equationLabel = new Label("EQUATION",labelStyle);
        Label scoreNumber = new Label("0",labelStyle);
        Label timerNumber = new Label("0",labelStyle);
        ImageButton refreshButton = new ImageButton(new ImageButton.ImageButtonStyle());

        goalButton = new TextButton("0",operatorButtonStyle); //TODO: style
        infoRight.add(goalLabel).left();
        infoRight.row();
        infoRight.add(goalButton).width(cellSize-10).height(cellSize-10);
        infoLeft.add(scoreLabel).expand(true,false);
        infoLeft.add(timerLabel).expand(true, false);;
        infoLeft.row();
        infoLeft.add(scoreNumber);
        infoLeft.add(timerNumber);
        infoLeft.add(refreshButton).width(30).height(30);
        refreshButton.setBackground(new ButtonBackground(new Color(0,0,0,1)));
        infoLeft.row();
        infoLeft.add(equationLabel).colspan(2).expand(true,false);
        infoTable.add(infoLeft).width(2*Gdx.graphics.getWidth() / 3).height(Gdx.graphics.getHeight()-table.getHeight());
        infoTable.add(infoRight).width(Gdx.graphics.getWidth() / 3).height(Gdx.graphics.getHeight()-table.getHeight());
        infoTable.setWidth(Gdx.graphics.getWidth());
        infoTable.setBackground(new ButtonBackground(new Color(203/255f,203/255f,203/255f,1)));
        infoLeft.debug();
        infoRight.debug();

        rootTable = new Table();
        rootTable.setHeight(Gdx.graphics.getHeight());
        rootTable.setWidth(Gdx.graphics.getWidth());
        //rootTable.debug();
        rootTable.setFillParent(true);
        rootTable.add(infoTable).height(Gdx.graphics.getHeight() - table.getHeight());
        rootTable.row();
        rootTable.add(table).bottom();
        stage.addActor(rootTable);
        Gdx.input.setInputProcessor(stage);
    }

    public void flashGrid(String type) {
        if (type.equalsIgnoreCase("operator")) {
            output = "pick an operator";
        } else if (type.equalsIgnoreCase("number")) {
            output = "pick a number";
        }
    }

    public MathGame getGame(){
        return this.game;
    }

    public void setOutput(String text, String type) {
        if (type.equalsIgnoreCase("clear"))
            output = text;
        else if (type.equalsIgnoreCase("add"))
            output += text;
    }

    public void setEquation(String text, String type) {
        if (type.equalsIgnoreCase("clear"))
            equation = text;
        else if (type.equalsIgnoreCase("add"))
           equation += text;
    }

    @Override
    public void render(float delta) {
        goalButton.setText(Integer.toString(grid.getResult()));
        Gdx.gl.glClearColor(238/255f, 238/255f, 238/255f, 1f);
        Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT);
        font.setColor(1f, 1f, 1f, 1f);
        stage.draw();
        Table.drawDebug(stage);
        spriteBatch.begin();
        font.draw(spriteBatch, "gameScreen", Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight());
        font.draw(spriteBatch, output, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() - font.getLineHeight());
        font.draw(spriteBatch, equation, Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() - (font.getLineHeight()*2));
        //font.draw(spriteBatch, "need to get: " + grid.getResult() + "", Gdx.graphics.getWidth() / 2, Gdx.graphics.getHeight() - (font.getLineHeight()*3));
        spriteBatch.end();
    }


    @Override
    public void resize(int width, int height) {

    }


    @Override
    public void show() {
        // called when this screen is set as the screen with game.setScreen();
        safeTimer = 0;
        while (safeTimer < 5)
            safeTimer++;
        // because InputListener touchUp method is called immediately otherwise
    }


    @Override
    public void hide() {
        // called when current screen changes from this to a different screen
    }


    @Override
    public void pause() {
    }


    @Override
    public void resume() {
    }


    @Override
    public void dispose() {
        // never called automatically
    }
}

class ButtonBackground implements Drawable {
    private Color color;
    //private TextureRegion tRegion;
    private Pixmap pixmap;
    private float LWidth,RWidth,THeight,BHeight,MinWidth,MinHeight;
    public ButtonBackground(Color color){
        this.color = color;
        pixmap = new Pixmap( 64, 64, Pixmap.Format.RGBA8888 );
        pixmap.setColor(color);
        pixmap.fill();
    }
    public void draw (SpriteBatch batch, float x, float y, float width, float height){
        Texture texture = new Texture(pixmap);
        TextureRegion tRegion = new TextureRegion(texture);
        batch.setColor(color);
        batch.draw(tRegion, x, y, width, height);
        //batch.setColor(Color.BLACK);
        //batch.draw(tRegion,x,y,1,height);
        texture.dispose();
    }
    //Stuff required by the interface
    public float getLeftWidth () {return this.LWidth;}
    public void setLeftWidth (float leftWidth) {this.LWidth = leftWidth;}
    public float getRightWidth () {return RWidth;}
    public void setRightWidth (float rightWidth) {this.RWidth = rightWidth;}
    public float getTopHeight () {return THeight;}
    public void setTopHeight (float topHeight) {this.THeight = topHeight;}
    public float getBottomHeight () {return BHeight;}
    public void setBottomHeight (float bottomHeight) {this.BHeight = bottomHeight;}
    public float getMinWidth () {return MinWidth;}
    public void setMinWidth (float minWidth) {this.MinWidth = minWidth;}
    public float getMinHeight () {return MinHeight;}
    public void setMinHeight (float minHeight) {this.MinHeight = minHeight;}
}
